/* Copyright 1990, 1991, 1992 Y&Y, Inc.
   Copyright 2007 TeX Users Group

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   02110-1301 USA.  */

/* Program to try and unreverse reversed subpaths 
 *          	
 * program to try and split curveto's at extrema 
 * program to try and recombine curveto's generated that way 
 * mostly of use in trying to beat Toal & Raine fonts into shape 
 *
 * to correct winding number problems use   unwind -u <file> 
 * to produce outlines in proper format use unwind -x <file> */

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
/* #include <float.h> */

#define MAXLINE 256
/* #define MAXKNOTS 512 */
/* #define MAXKNOTS 1024 */
#define MAXKNOTS 2048
/* #define MAXSUBPATHS 8 */
/* #define MAXSUBPATHS 16 */
/* #define MAXSUBPATHS 32 */
/* #define MAXSUBPATHS 64 */
#define MAXSUBPATHS 128

#define MAXCHRS 256

#define CURRENTDIRECT 1 	/* put output file in current directory */

int hits[MAXCHRS];				/* which characters were modified */
int seen[MAXCHRS];				/* which characters were seen */

FILE *fp_in, *fp_out;			/* so can use in giveup */

FILE *errout=stdout;

/*****************************************************************/

struct subpath { /* structure for subpaths */
  int xll; int yll; int xur; int yur;
  int start; int end; int reverse; int outside;
  double turn; double area;
};

struct knot {	/* structure for a knot */
	int x; int y; char code;
};

char *ext = "unw";			/* default extension for output file */

char *task;					/* for error message information output */

static struct knot knots[MAXKNOTS];

static struct subpath subpaths[MAXSUBPATHS];

static char line[MAXLINE];

int nknot, nsubpath; /* number of knots, number of subpaths */

int chr;					/* character currently working on */

int debugflag=1;			/* enable extra checking */
int verboseflag=0;			/* show details of winding number calc */
int detailflag=0;			/* show details of winding number calc */
int complainopen=0;			/* complain about open paths */
int showflag=0; 			/* show details of merging of curveto's */
int traceflag=0;			/* show details of character read and analyze */
int splitextremaflag=0;		/* break at extrema */
int mergeflag=0;			/* merge short curveto's generated by splitting */
int moremerges=0;			/* reorder path at end and try again */
int flattenflag=0;			/* turn almost flat curveto's into lineto's */
int straightenflag=1;		/* turn completely flat curveto's into lineto's */
int combineflag=0;			/* combine colinear lineto's */
int colinearflag=1;			/* combine exactly colinear lineto's */
int complainflag=0;			/* complain about bad winding number */
int crossoverflag=0;		/* fix cross-overs */
int unwindflag=0;			/* split path, get winding, reread and reverse */
int reverseflag=1;			/* reverse paths if needed */
int nulloutput=0;			/* suppress output */
int showcrosses=0;			/* show details of crossovers */
int closepaths=0;			/* output final lineto even if not needed */

char *path = "";	/* path for output files */

int extenflag=0;			/* next arg is file name extension */
int pathflag=0;				/* next arg is path for output */

int splits=0;				/* how many curveto's have been split */
int merges=0;				/* how many curveto's have been merged */
int flattens=0;				/* how many curveto's have been linearized */
int straightens=0;			/* how many curveto's have been linearized */
int combines=0;				/* how many lineto's have been combined */
int colinears=0;			/* how many lineto's have been combined */

int newstyle=0;				/* non-zero => new style outlines */

double pi = 3.141592653;

/* ---------------------------------------------------------------- */

#define ABS(x) (((x) < 0) ? (-x) : (x))
#define MAX(x, y) (((x) < (y)) ? (y) : (x))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))

/* int levepsilon = 6; 	*/	/* allowed departure from level line */
/* int lenepsilon = 6; 	*/	/* allowed departure from straight line */

double tantiny = 0.1; 		/* allow 6 degrees between segments  */
double tansmall = 0.3;		/* allow 17 degree turning when merging */

/* int mlength = 80;	*/	/* longest curveto considered for merge */
/* int msplit = 16;		*/  /* largest movement of knot allowed in merge */

int round(double x) {
	if (x < 0) return (- (round (- x)));
	else return (int) (x + 0.5);
}

/* Approx sqrt of sum of squares  for range x > 0, y > 0, x > y */
/* r approx a * x + b * x, a = 2/(1+sqrt(4-2*sqrt(2))), b = (sqrt(2)-1)*a */
/* return (int) sqrt ((double) x * (double) x + (double) y * (double) y); */

/*
int radius(int x, int y) {
	int t;
	if (x < 0) x = -x;
	if (y < 0) y = -y;
	if (x < y) {t = x; x = y; y = t;}
	return (int) (((long) x * 960L + (long) y * 398l) / 1000L);
} */

/*
void checkintegrity(int start, int end) {
	assert(knots[start].code == 'M');
	assert(knots[end-1].code == 'H');
	assert(knots[end-1].x == knots[start].x);
	assert(knots[end-1].y == knots[start].y);
	assert(knots[end-2].code == 'L' ||	knots[end-2].code == 'C');
	assert(knots[end-2].x == knots[start].x);
	assert(knots[end-2].y == knots[start].y);	
} */

/* move all knots down by dk starting with knot start */
/* may need to preserve code of knot (start - dk) ... */
int shiftdown(int start, int end, int dk) { /* shift knots down by dk */
	int i;
/*	char code;  */

	assert (start < end);
	if (debugflag != 0) assert(knots[end-1].code == 'H');
	assert(start >= dk);
/*	code = knots[start - dk].code;  */
	for (i = start; i < end; i++) knots[i - dk] = knots[i];
/* 	knots[start - dk].code = code; */
	end = end - dk; 
	return end;
}

/* move all knots up by dk starting with knot (k - dk)  */
/* there will be two copies of knots (start - dk) through knot (start - 1) */
int shiftup(int start, int end, int dk) { 
	int i;

	assert (start < end);
	if (debugflag != 0) assert(knots[end-1].code == 'H');
	end = end + dk;
	assert(start >= dk);
 	assert(start + dk < MAXKNOTS); 
	for (i = end-1; i > start; i--) 
		knots[i] = knots[i - dk];
	return end;
}

double lepsilon = 8.0; /* premissible lateral offset in flatten line */
double sepsilon = 6.0; /* 4.0 premissible lateral offset in combine line */

/* check if point is near given straight line */

int nearline(int xs, int ys, int xm, int ym, int xf, int yf, double eps) {
	double fdx, fdy, len;
	double cros, rho;

	fdx = (double) (xf - xs); fdy = (double) (yf - ys); 
	cros = (double) ys * (double) xf - (double) xs * (double) yf;
	len = ABS(fdx) + ABS(fdy);  /* favour slanted lines for this */
/*	len = sqrt(fdx * fdx + fdy * fdy); */
	rho = fdy * (double) xm - fdx * (double) ym + cros;
	if (ABS(rho) < len * eps) return -1;
	else return 0;
} 
		
/* used to avoid combining short, but sharply turning curve segments */

int smallangle(int x0, int y0, int x1, int y1, 
				int  x2, int y2, int x3, int y3) {
	int dx1, dy1, dx3, dy3;
	double cros, dot;
	double tantheta;
	
	dx1 = x1 - x0; dy1 = y1 - y0; dx3 = x3 - x2, dy3 = y3 - y2;
	dot = (double) dx1 * (double) dx3 + (double) dy1 * (double) dy3;
	if(dot < 0L) return 0;	
	cros = (double) dx1 * (double) dy3 - (double) dx3 * (double) dy1;
	if (dot <= 0L) return 0;
	tantheta = (double) cros / (double) dot;
	if (ABS(tantheta) < tantiny) return -1;
	else return 0; 
} 

/* see if curveto is nearly flat */
	
int flatcurve(int x0, int y0, int x1, int y1, 
				int  x2, int y2, int x3, int y3) {
	if (x0 == x1 && x1 == x2 && x2 == x3) return -1;	/* 94/Feb/8 */
	if (y0 == y1 && y1 == y2 && y2 == y3) return -1;	/* 94/Feb/8 */
	if ((nearline(x0, y0, x1, y1, x3, y3,  lepsilon)  != 0) &&
		(nearline(x0, y0, x2, y2, x3, y3,  lepsilon)  != 0) &&
		(smallangle(x0, y0, x1, y1, x2, y2, x3, y3) != 0)) return -1;
	else return 0;
} 

int mincurve(int za, int zb, int zc, int zd) {	/* min of four numbers */
	int zab, zcd;
	zab = MIN(za, zb); zcd = MIN(zc, zd);
	return MIN(zab, zcd);
}

int maxcurve(int za, int zb, int zc, int zd) { /* max of four numbers */
	int zab, zcd;
	zab = MAX(za, zb); zcd = MAX(zc, zd);
	return MAX(zab, zcd);
}

int mindy=6; 		/* try not to flatten bowed serifs */
int mindx=2; 		/* try not to flatten tapered stems */

/* turn flat curveto's into lineto's */

int flattencurves(int start, int end) {
	int xmin, xmax, ymin, ymax;
	int k, dy, dx, xa, ya, xb, yb, xc, yc, xd, yd;
	
	for (k = start + 3; k < end; k++) {
		if (knots[k].code == 'C') {
			ya=knots[k-3].y;		yb=knots[k-2].y;
			yc=knots[k-1].y;		yd=knots[k].y;
			ymin = mincurve(ya, yb, yc, yd);
			ymax = maxcurve(ya, yb, yc, yd);
			dy = ymax - ymin;
			if (ABS(dy) < mindy) continue;
			xa=knots[k-3].x; 		xb=knots[k-2].x; 
			xc=knots[k-1].x; 		xd=knots[k].x;   
			xmin = mincurve(xa, xb, xc, xd);
			xmax = maxcurve(xa, xb, xc, xd);
			dx = xmax - xmin; 
			if (ABS(dx) < mindx) continue;
			if (flatcurve(xa, ya, xb, yb,  xc, yc, xd, yd) != 0) {
/*				knots[k].code = 'L'; */
				end = shiftdown(k, end, 2); 
				knots[k-2].code = 'L';
/*				assert(knots[k-2].code == 'L'); */
				flattens++;
				hits[chr]++;
				k--; 				/* not useful ? */
			}
		}
	}
	return end;
}

int straightencurves(int start, int end) {			/* 1994/Feb/8 */
	int xmin, xmax, ymin, ymax;
	int k, dy, dx, xa, ya, xb, yb, xc, yc, xd, yd;
	
	for (k = start + 3; k < end; k++) {
		if (knots[k].code == 'C') {
			ya=knots[k-3].y;		yb=knots[k-2].y;
			yc=knots[k-1].y;		yd=knots[k].y;
			ymin = mincurve(ya, yb, yc, yd);
			ymax = maxcurve(ya, yb, yc, yd);
			dy = ymax - ymin; 
/*			if (ABS(dy) < mindy) continue; */
			xa=knots[k-3].x; 		xb=knots[k-2].x; 
			xc=knots[k-1].x; 		xd=knots[k].x;   
			xmin = mincurve(xa, xb, xc, xd);
			xmax = maxcurve(xa, xb, xc, xd);
			dx = xmax - xmin; 
/*			if (ABS(dx) < mindx) continue; */
			if (dx == 0 || dy == 0) {				
/*				knots[k].code = 'L'; */
				end = shiftdown(k, end, 2); 
				knots[k-2].code = 'L';
/*				assert(knots[k-2].code == 'L'); */
				straightens++;
				hits[chr]++;
				k--; 				/* not useful ? */
			}
		}
	}
	return end;
}

/* don't mess with near vertical and near horizontal lines */

int nottang(int xs, int ys, int xm, int ym, int xf, int yf) {
	int dx, dy;
	dx = xs - xm; dy = ys - ym;
	if (ABS(dx) <= 1 || ABS(dy) <= 1) return 0;
	dx = xf - xm; dy = yf - ym;
	if (ABS(dx) <= 1 || ABS(dy) <= 1) return 0;
	return -1;
} 

int combinelines(int start, int end) {  /* combine colinear linetos */
	int k, xa, ya, xb, yb, xc, yc;
	
	for (k = start + 2; k < end; k++) {
		if (knots[k].code == 'L' && knots[k-1].code == 'L') {
			xa=knots[k-2].x; ya=knots[k-2].y;
			xb=knots[k-1].x; yb=knots[k-1].y;
			xc=knots[k].x;   yc=knots[k].y;
			if (nottang(xa, ya, xb, yb, xc, yc) != 0 &&
				nearline(xa, ya, xb, yb, xc, yc,  sepsilon) != 0) {
				end = shiftdown(k, end, 1); 
				combines++;
				hits[chr]++;
				k--; 		/* a little dangerous - accumulate errors ? */
			}
		}
	}
	return end;
}  

int mergelines(int start, int end) {  /* combine colinear linetos */
	int k, xa, ya, xb, yb, xc, yc;
	
	for (k = start + 2; k < end; k++) {
		if (knots[k].code == 'L' && knots[k-1].code == 'L') {
			xa=knots[k-2].x; ya=knots[k-2].y;
			xb=knots[k-1].x; yb=knots[k-1].y;
			xc=knots[k].x;   yc=knots[k].y;
			if ((xa == xb && xb == xc) || (ya == yb && yb == yc)) {
				end = shiftdown(k, end, 1); 
				colinears++;
				hits[chr]++;
				k--;
			}
		}
	}
	return end;
}  

void showsubpathsub(int start, int end) {
	int k;
	printf("\n");
	printf("Subpath start %d end %d\n", start, end);
	for (k = start; k < end; k++) {
/*		 if (closepaths == 0 && k == end-2 && knots[k].code == 'L') {
			 if (knots[k].x == knots[start].x &&
				 knots[k].y == knots[start].y) continue;
		 } */
		 printf("%d %d %c \n", knots[k].x, knots[k].y, knots[k].code);
	}
}

void showsubpath(int k) {
	int start, end;
	start = subpaths[k].start;
	end = subpaths[k].end;	
	showsubpathsub(start, end);
}

/* rearrange knots so something else appears in first spot */

int rearrange(int start, int end) {
	int k, i, code;
	if (knots[start].code != 'M') {
		showsubpathsub(start, end);
		fflush(stdout);
		(void) _getch();   
	}
	fflush(stdout);
	if (debugflag != 0) {
		assert(knots[start].code == 'M');
		assert(knots[end-1].code == 'H');
		assert(knots[end-1].x == knots[start].x);
		assert(knots[end-1].y == knots[start].y);
		assert(knots[end-2].code == 'L' ||	knots[end-2].code == 'C');
		assert(knots[end-2].x == knots[start].x);
		assert(knots[end-2].y == knots[start].y);	
	}
	k = (start + end) / 2 ;
	for(;;) {
		code = knots[k].code;
		if (code == 'L' || code == 'C') break;
		k++; 
		if (k >= end) k = start;
	}
	assert(end + k + 1 < MAXKNOTS);
	for (i = start; i < k; i++) knots[i - start + end - 1] = knots[i+1];
	for (i = start; i < end; i++) knots[i] = knots[i + k - start];
	knots[start].code = 'M';
	knots[end - 1] = knots[start];
	knots[start].code = 'M';
	knots[end - 1].code = 'H';
	if (knots[start].code != 'M') {
		showsubpathsub(start, end);
		fflush(stdout);
		(void) _getch();   
	}
	fflush(stdout);
	if (debugflag != 0) {
		assert(knots[start].code == 'M');
		assert(knots[end-1].code == 'H');
		assert(knots[end-1].x == knots[start].x);
		assert(knots[end-1].y == knots[start].y);
		assert(knots[end-2].code == 'L' ||	knots[end-2].code == 'C');
		assert(knots[end-2].x == knots[start].x);
		assert(knots[end-2].y == knots[start].y);	
	}
	return end;
}
	
/* check whether Bezier curve has extremum */

double extrema(int z0, int z1, int z2, int z3) {
	int minz, maxz;
	int az, bz, cz;
	double discr;
	double rootdiscr, root, root1, root2;

	minz = MIN(z0, z3); maxz = MAX(z0, z3);
	if (z1 >= minz && z1 <= maxz && z2 >= minz && z2 <= maxz) return -1.0;
	az = z3 - 3 * (z2 - z1) - z0;
	bz = 3 * (z2 - 2 * z1 + z0);
	cz = 3 * (z1 - z0);
	if (az == 0) {
		if (bz == 0) return -1.0;
		else {
			root = - (double) cz / (2.0 * (double) bz);
			if (root > 0.0 && root < 1.0) return root;
			else return -1.0;
		}
	}
	discr = (double) bz * (double) bz - 3 * (double) az * (double) cz;
	if (discr < 0) return -1.0;
	rootdiscr = sqrt((double) discr);
	root1 = (- (double) bz + rootdiscr) / (3.0 * (double) az);
	if (root1 > 0.0 && root1 < 1.0) return root1;
	root2 = (- (double) bz - rootdiscr) / (3.0 * (double) az);
	if (root2 > 0.0 && root2 < 1.0) return root2;
	return -1.0;
}

/* split Bezier curve at t = alp */

void splitextrema(int k, double alp) {
	double f0, f1, f2, f3;
	double a, b, c, d, mal;
	double an, bn, cn, dn;

	f0 = (double) knots[k-3].x;
	f1 = (double) knots[k-2].x;
	f2 = (double) knots[k-1].x;
	f3 = (double) knots[k].x;

	a = (f3 - f0) - 3.0 * (f2 - f1);
	b = 3.0 * (f2 - 2.0 * f1 + f0);
	c = 3.0 * (f1 - f0);	
	d = f0;
	
	an = a * alp * alp * alp;
	bn = b * alp * alp;
	cn = c * alp;
	dn = d;
	
/*	assert(knots[k-3].x == f0); */
/*	assert(knots[k-3].x == round(dn)); */
	if (knots[k-3].x != round(dn)) {
		fprintf(errout, "knots[%d-3].x %lg round(dn)\n", 
			k, knots[k-3].x, round(dn));;
	}
	knots[k - 2].x = round(dn + cn / 3.0);
	knots[k - 1].x = round(dn + (2.0 * cn + bn) / 3.0);
	knots[k].x = round(dn + cn + bn + an);

	mal = 1.0 - alp;
	an =  a * mal * mal * mal;
	bn =  (3.0 * a * alp + b) * mal * mal;
	cn =  (alp * (3.0 * a * alp + 2.0 * b) + c) * mal;
	dn =  alp * ( alp * (alp * a + b) + c) + d;

	assert(knots[k].x == round(dn));
	knots[k+1].x = round(dn + cn / 3.0);
	knots[k+2].x = round(dn + (2.0 * cn + bn) / 3.0);
	assert(knots[k+3].x == round(f3));
/*	assert(knots[k+3].x == round(dn + cn + bn + an)); */
	if (knots[k+3].x != round(dn+cn+bn+an)) {
		fprintf(errout, "knots[%d+3].x %lg round(dn+cn+bn+an)\n", 
			k, knots[k+3].x, round(dn+cn+bn+an));;
	}

	f0 = (double) knots[k-3].y;
	f1 = (double) knots[k-2].y;
	f2 = (double) knots[k-1].y;
	f3 = (double) knots[k].y;

	a = (f3 - f0) - 3.0 * (f2 - f1);
	b = 3.0 * (f2 - 2.0 * f1 + f0);
	c = 3.0 * (f1 - f0);	
	d = f0;
	
	an = a * alp * alp * alp;
	bn = b * alp * alp;
	cn = c * alp;
	dn = d;
	
/*	assert(knots[k-3].y == f0); */
/*	assert(knots[k-3].y == round(dn)); */
	if (knots[k-3].y != round(dn)) {
		fprintf(errout, "knots[%d-3].y %lg round(dn)\n", 
			k, knots[k-3].y, round(dn));;
	}
	knots[k - 2].y = round(dn + cn / 3.0);
	knots[k - 1].y = round(dn + (2.0 * cn + bn) / 3.0);
	knots[k].y = round(dn + cn + bn + an);

	mal = 1.0 - alp;
	an =  a * mal * mal * mal;
	bn =  (3.0 * a * alp + b) * mal * mal;
	cn =  (alp * (3.0 * a * alp + 2.0 * b) + c) * mal;
	dn =  alp * ( alp * (alp * a + b) + c) + d;

	assert(knots[k].y == round(dn));
	knots[k+1].y = round(dn + cn / 3.0);
	knots[k+2].y = round(dn + (2.0 * cn + bn) / 3.0);
	assert(knots[k+3].y == round(f3));
/*	assert(knots[k+3].y == round(dn + cn + bn + an)); */
	if (knots[k+3].y != round(dn+cn+bn+an)) {
		fprintf(errout, "knots[%d+3].y %lg round(dn+cn+bn+an)\n", 
			k, knots[k+3].y, round(dn+cn+bn+an));;
	}
	splits++;		/* count it */
	hits[chr]++;
}

double distance (double xa, double ya, double xb, double yb) {
	double dx, dy;
	dx = xb - xa; dy = yb -ya;
	return sqrt (dx * dx + dy * dy);
}

#define POLY(a, b, c, d, ft) ((((a) * (ft) + (b)) * (ft) + (c)) * (ft) + (d))

double bezier(int z0, int z1, int z2, int z3, double ft) {
	 double fz0, fz1, fz2, fz3;
	 double az, bz, cz;
	 
	 fz0 = (double) z0; 	 fz1 = (double) z1; 
	 fz2 = (double) z2; 	 fz3 = (double) z3; 
	 cz = (fz1 - fz0) * 3.0; 
	 bz = ((fz2 - fz1) - (fz1 - fz0)) * 3.0; 
	 az = (fz3 - fz0) + 3.0 * (fz1 - fz2);
	 
	 return POLY(az, bz, cz, fz0, ft);
} 

int nearvertical(double dx, double dy) {
	if (ABS(dx) < tansmall * ABS(dy)) return -1;
	else return 0;
}

int nearhorizontal(double dx, double dy) {
	if (ABS(dy) < tansmall * ABS(dx)) return -1;
	else return 0;
}

	double acrosslim = 5.0; /* was 2.0 */
	double alonglim = 12.0;	/* was 5.0 */
	double ftlim = 1.5;		/* limit on t at tangency point */

/* new short curveto is from k-3 to k, old longer curveto from k to k+3 */
/* the vertical tangent occurs at k-3 and must be preserved */
/* see if can patch together - vertical tangent */

int trypatchxup(int k) {
	int xv, yv, x0, y0, x1, y1, x2, y2, x3, y3;
	double rbv, rbt, rbn, ft, fxv, fyv, fxn, fyn, fdx, fdy;
	double fx0, fx1, fx2, fx3, fy0, fy1, fy2, fy3;
	double ax, bx, cx, dx, ay, by, cy, dy;
	 
	if (mergeflag == 0) return 0;
/*	if (k + 3 > end - 2) return 0; */
	xv = knots[k-3].x; yv = knots[k-3].y; /* place of tangency */
	if (showflag != 0) printf("\nXUP: tangent at (%d, %d) ", xv, yv);
	fxv = (double) xv; fyv = (double) yv;
	assert (knots[k-3].x == knots[k-2].x);
	x3 = knots[k].x; y3 = knots[k].y;	
	x2 = knots[k+1].x; y2 = knots[k+1].y;		
	fx3 = (double) x3; fy3 = (double) y3;
	fx2 = (double) x2; fy2 = (double) y2;
/* check on angle of turn in short segment */
	if (showflag != 0) printf("- turning (%lg %lg)", fx3 - fx2, fy3 - fy2);
	if (nearvertical(fx3 - fx2, fy3 - fy2) == 0) {
		if (showflag != 0) {
			printf(" FAILED\n");
/*			(void) getch(); */
		}
		return 0;
	}
	rbv = distance(fxv, fyv, fx3, fy3);
	rbt = distance(fx3, fy3, fx2, fy2);
	assert (rbt != 0.0);
/*	assert (rbv != 0.0); */
/*	if (rbv == 0.0) combine ? */
	ft = 1.0 + rbv/(3.0 * rbt);		/* estimated t at xv, yv */

	if (showflag != 0) printf("- estimated t = %lg ", ft);
	
	assert (ft >= 1.0);
	if (ft > ftlim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;			/* don't expect to win */
	}

	/* compute coefficients of the two cubics */
	
	x0 = knots[k+3].x; 	x1 = knots[k+2].x;
	fx0 = (double) x0; 	 fx1 = (double) x1; 
	dx = fx0;
	cx = (fx1 - fx0) * 3.0; 
	bx = ((fx2 - fx1) - (fx1 - fx0)) * 3.0; 
	ax = (fx3 - fx0) + 3.0 * (fx1 - fx2);
	 
	fxn = POLY(ax, bx, cx, fx0, ft); 
	assert (fxn == bezier(x0, x1, x2, x3, ft));

	y0 = knots[k+3].y; 	y1 = knots[k+2].y;
	fy0 = (double) y0; 	 fy1 = (double) y1; 
	dy = fy0;
	cy = (fy1 - fy0) * 3.0; 
	by = ((fy2 - fy1) - (fy1 - fy0)) * 3.0; 
	ay = (fy3 - fy0) + 3.0 * (fy1 - fy2);
	 
	fyn = POLY(ay, by, cy, fy0, ft); 
	assert (fyn == bezier(y0, y1, y2, y3, ft));

	if (showflag != 0) printf("\nOLD: (%d %d) (%d %d) (%d %d) (%d %d)\n",
		x0, y0, x1, y1, x2, y2, x3, y3);

	fdx = fxv - fxn; fdy = fyv - fyn;
	if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
/*  not clear the following is worth it */
/* 	or maybe always do this ? */
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		rbn = distance(fx3, fy3, fxn, fyn);
		ft = 1.0 + (ft - 1.0) * rbv / rbn;
		fxn = POLY(ax, bx, cx, fx0, ft);
		fyn = POLY(ay, by, cy, fy0, ft);
		fdx = fxv - fxn; fdy = fyv - fyn;		
		if (showflag != 0) printf("Adjusting t = %lg\n", ft);
		if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
	}
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0; /* not close enough */
	}
	
	/* compute coefficients of extended cubics */
	
	ax = ax * ft * ft * ft;
	bx = bx * ft * ft;
	cx = cx * ft;
	
	ay = ay * ft * ft * ft;
	by = by * ft * ft;
	cy = cy * ft;
	
	/* compute new knots */

	/* x0 unchanged */
	x1 = round(dx + cx / 3.0);
	x2 = round(dx + (2.0 * cx + bx) / 3.0);
	x3 = round(dx + cx + bx + ax);

	/* y0 unchanged */
	y1 = round(dy + cy / 3.0);
	y2 = round(dy + (2.0 * cy + by) / 3.0);
	y3 = round(dy + cy + by + ay);

	/* snap to knots */

	x3 = xv; y3 = yv; x2 = xv;
	
	/* check that new curve passes near (xb, yb) */
	
 	fxn = bezier(x0, x1, x2, x3, 1/ft); 
	fyn = bezier(y0, y1, y2, y3, 1/ft); 

	fdx = fxn - fx3; 	fdy = fyn - fy3; 		/* old values */
	if (showflag != 0) printf("- offset new (%lg, %lg) ", fdx, fdy);
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;	/* not close enough */
	}

	/* insert new knots, ready for shift down */
	/* worry about code at k - 3 ? */
	knots[k].x = x3;   knots[k].y = y3;
	knots[k+1].x = x2; knots[k+1].y = y2; 
	knots[k+2].x = x1; knots[k+2].y = y1; 
	assert(knots[k+3].x == x0); 
	assert(knots[k+3].y == y0); 
	assert (knots[k].x == knots[k-3].x);
	assert (knots[k].y == knots[k-3].y);	
	if (showflag != 0) printf("\nNEW: (%d %d) (%d %d) (%d %d) (%d %d) ",
		x0, y0, x1, y1, x2, y2, x3, y3);
	if (showflag != 0) {
		printf("SUCCESS\n");
/*		(void) getch(); */
	}
	merges++;			/* count it */
	hits[chr]++;
	return -1;
}

/* try to patch together - vertical tangent */
int trypatchxdown(int k) {
	int xv, yv, x0, y0, x1, y1, x2, y2, x3, y3;
	double rbv, rbt, rbn, ft, fxv, fyv, fxn, fyn, fdx, fdy;
	double fx0, fx1, fx2, fx3, fy0, fy1, fy2, fy3;
	double ax, bx, cx, dx, ay, by, cy, dy;
	 
	if (mergeflag == 0) return 0;
/*	if (k - 3 < start) return 0; */
	xv = knots[k+3].x; yv = knots[k+3].y; /* place of tangency */
	if (showflag != 0) printf("\nXDOWN: tangent at (%d, %d) ", xv, yv);
	fxv = (double) xv; fyv = (double) yv;
	assert (knots[k+3].x == knots[k+2].x);
	x3 = knots[k].x; y3 = knots[k].y;	
	x2 = knots[k-1].x; y2 = knots[k-1].y;
	fx3 = (double) x3; fy3 = (double) y3;
	fx2 = (double) x2; fy2 = (double) y2;
/* check on angle of turn in short segment */
	if (showflag != 0) printf("- turning (%lg %lg)", fx3 - fx2, fy3 - fy2);
	if (nearvertical(fx3 - fx2, fy3 - fy2) == 0) {
		if (showflag != 0) {
			printf(" FAILED\n");
/*			(void) getch(); */
		}
		return 0;
	}
	rbv = distance(fxv, fyv, fx3, fy3);
	rbt = distance(fx3, fy3, fx2, fy2);
	assert (rbt != 0.0);
/*	assert (rbv != 0.0); */
/*	if (rbv == 0.0) combine ? */
	ft = 1.0 + rbv/(3.0 * rbt);		/* estimated t at xv, yv */

	if (showflag != 0) printf("- estimated t = %lg ", ft);
	
	assert (ft >= 1.0);
	if (ft > ftlim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;			/* don't expect to win */
	}

	/* compute coefficients of the two cubics */
	
	x0 = knots[k-3].x; 	 x1 = knots[k-2].x;
	fx0 = (double) x0; 	 fx1 = (double) x1; 
	dx = fx0;
	cx = (fx1 - fx0) * 3.0; 
	bx = ((fx2 - fx1) - (fx1 - fx0)) * 3.0; 
	ax = (fx3 - fx0) + 3.0 * (fx1 - fx2);
	 
	fxn = POLY(ax, bx, cx, fx0, ft); 
	assert (fxn == bezier(x0, x1, x2, x3, ft));

	y0 = knots[k-3].y; 	 y1 = knots[k-2].y;
	fy0 = (double) y0; 	 fy1 = (double) y1; 
	dy = fy0;
	cy = (fy1 - fy0) * 3.0; 
	by = ((fy2 - fy1) - (fy1 - fy0)) * 3.0; 
	ay = (fy3 - fy0) + 3.0 * (fy1 - fy2);
	 
	fyn = POLY(ay, by, cy, fy0, ft); 
	assert (fyn == bezier(y0, y1, y2, y3, ft));

	if (showflag != 0) printf("\nOLD: (%d %d) (%d %d) (%d %d) (%d %d)\n",
		x0, y0, x1, y1, x2, y2, x3, y3);

	fdx = fxv - fxn; fdy = fyv - fyn;
	if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
/*  not clear the following is worth it */
/* 	or maybe always do this ? */
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		rbn = distance(fx3, fy3, fxn, fyn);
		ft = 1.0 + (ft - 1.0) * rbv / rbn;
		fxn = POLY(ax, bx, cx, fx0, ft);
		fyn = POLY(ay, by, cy, fy0, ft);
		fdx = fxv - fxn; fdy = fyv - fyn;		
		if (showflag != 0) printf("Adjusting t = %lg\n", ft);
		if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
	}
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0; /* not close enough */
	}
	
	/* compute coefficients of extended cubics */
	
	ax = ax * ft * ft * ft;
	bx = bx * ft * ft;
	cx = cx * ft;
	
	ay = ay * ft * ft * ft;
	by = by * ft * ft;
	cy = cy * ft;
	
	/* compute new knots */

	/* x0 unchanged */
	x1 = round(dx + cx / 3.0);
	x2 = round(dx + (2.0 * cx + bx) / 3.0);
	x3 = round(dx + cx + bx + ax);

	/* y0 unchanged */
	y1 = round(dy + cy / 3.0);
	y2 = round(dy + (2.0 * cy + by) / 3.0);
	y3 = round(dy + cy + by + ay);

	/* snap to knots */

	x3 = xv; y3 = yv; x2 = xv;
	
	/* check that new curve passes near (xb, yb) */
	
 	fxn = bezier(x0, x1, x2, x3, 1/ft); 
	fyn = bezier(y0, y1, y2, y3, 1/ft); 

	fdx = fxn - fx3; 	fdy = fyn - fy3; 		/* old values */
	if (showflag != 0) printf("- offset new (%lg, %lg) ", fdx, fdy);
	if (ABS(fdx) > acrosslim || ABS(fdy) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;	/* not close enough */
	}

	/* insert new knots, ready for shift down */
	/* worry about code at k - 3 ? */
	knots[k+3].x = x3; knots[k+3].y = y3;
	knots[k+2].x = x2; knots[k+2].y = y2; 
	knots[k+1].x = x1; knots[k+1].y = y1; 
	knots[k].x = x0;   knots[k].y = y0; 
/*	x0 = knots[k-3].x; 	*/ /*	y0 = knots[k-3].y; 	*/
	assert(knots[k-3].x == knots[k].x);
	assert(knots[k-3].y == knots[k].y);	
	if (showflag != 0) printf("\nNEW: (%d %d) (%d %d) (%d %d) (%d %d) ",
		x0, y0, x1, y1, x2, y2, x3, y3);
	if (showflag != 0) {
		printf("SUCCESS\n");
/*		(void) getch(); */
	}
	merges++;			/* count it */
	hits[chr]++;
	return -1;
}

/* new short curveto is from k-3 to k, old longer curveto from k to k+3 */
/* the horizontal tangent occurs at k-3 and must be preserved */
/* try to patch together - horizontal tangent */ 
int trypatchyup(int k) {
	int xv, yv, x0, y0, x1, y1, x2, y2, x3, y3;
	double rbv, rbt, rbn, ft, fxv, fyv, fxn, fyn, fdx, fdy;
	double fx0, fx1, fx2, fx3, fy0, fy1, fy2, fy3;
	double ax, bx, cx, dx, ay, by, cy, dy;
	 
	if (mergeflag == 0) return 0;
/*	if (k + 3 > end - 2) return 0; */
	xv = knots[k-3].x; yv = knots[k-3].y; /* place of tangency */
	if (showflag != 0) printf("\nYUP: tangent at (%d, %d) ", xv, yv);
	fxv = (double) xv; fyv = (double) yv;
	assert (knots[k-3].y == knots[k-2].y);
	x3 = knots[k].x; y3 = knots[k].y;	
	x2 = knots[k+1].x; y2 = knots[k+1].y;		
	fx3 = (double) x3; fy3 = (double) y3;
	fx2 = (double) x2; fy2 = (double) y2;
/* check on angle of turn in short segment */
	if (showflag != 0) printf("- turning (%lg %lg)", fx3 - fx2, fy3 - fy2);
	if (nearhorizontal(fx3 - fx2, fy3 - fy2) == 0) {
		if (showflag != 0) {
			printf(" FAILED\n");
/*			(void) getch(); */
		}
		return 0;
	}
	rbv = distance(fxv, fyv, fx3, fy3);
	rbt = distance(fx3, fy3, fx2, fy2);
	assert (rbt != 0.0);
/*	assert (rbv != 0.0); */
/*	if (rbv == 0.0) combine ? */
	ft = 1.0 + rbv/(3.0 * rbt);		/* estimated t at xv, yv */

	if (showflag != 0) printf("- estimated t = %lg ", ft);
	
	assert (ft >= 1.0);
	if (ft > ftlim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;			/* don't expect to win */
	}

	/* compute coefficients of the two cubics */
	
	x0 = knots[k+3].x; 	x1 = knots[k+2].x;
	fx0 = (double) x0; 	 fx1 = (double) x1; 
	dx = fx0;
	cx = (fx1 - fx0) * 3.0; 
	bx = ((fx2 - fx1) - (fx1 - fx0)) * 3.0; 
	ax = (fx3 - fx0) + 3.0 * (fx1 - fx2);
	 
	fxn = POLY(ax, bx, cx, fx0, ft); 
	assert (fxn == bezier(x0, x1, x2, x3, ft));

	y0 = knots[k+3].y; 	y1 = knots[k+2].y;
	fy0 = (double) y0; 	 fy1 = (double) y1; 
	dy = fy0;
	cy = (fy1 - fy0) * 3.0; 
	by = ((fy2 - fy1) - (fy1 - fy0)) * 3.0; 
	ay = (fy3 - fy0) + 3.0 * (fy1 - fy2);
	 
	fyn = POLY(ay, by, cy, fy0, ft); 
	assert (fyn == bezier(y0, y1, y2, y3, ft));

	if (showflag != 0) printf("\nOLD: (%d %d) (%d %d) (%d %d) (%d %d)\n",
		x0, y0, x1, y1, x2, y2, x3, y3);

	fdx = fxv - fxn; fdy = fyv - fyn;
	if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
/*  not clear the following is worth it */
/* 	or maybe always do this ? */
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		rbn = distance(fx3, fy3, fxn, fyn);
		ft = 1.0 + (ft - 1.0) * rbv / rbn;
		fxn = POLY(ax, bx, cx, fx0, ft);
		fyn = POLY(ay, by, cy, fy0, ft);
		fdx = fxv - fxn; fdy = fyv - fyn;		
		if (showflag != 0) printf("Adjusting t = %lg\n", ft);
		if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
	}
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0; /* not close enough */
	}
	
	/* compute coefficients of extended cubics */
	
	ax = ax * ft * ft * ft;
	bx = bx * ft * ft;
	cx = cx * ft;
	
	ay = ay * ft * ft * ft;
	by = by * ft * ft;
	cy = cy * ft;
	
	/* compute new knots */

	/* x0 unchanged */
	x1 = round(dx + cx / 3.0);
	x2 = round(dx + (2.0 * cx + bx) / 3.0);
	x3 = round(dx + cx + bx + ax);

	/* y0 unchanged */
	y1 = round(dy + cy / 3.0);
	y2 = round(dy + (2.0 * cy + by) / 3.0);
	y3 = round(dy + cy + by + ay);

	/* snap to knots */

	x3 = xv; y3 = yv; y2 = yv;
	
	/* check that new curve passes near (xb, yb) */
	
 	fxn = bezier(x0, x1, x2, x3, 1/ft); 
	fyn = bezier(y0, y1, y2, y3, 1/ft); 

	fdx = fxn - fx3; 	fdy = fyn - fy3; 		/* old values */
	if (showflag != 0) printf("- offset new (%lg, %lg) ", fdx, fdy);
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;	/* not close enough */
	}

	/* insert new knots, ready for shift down */
	/* worry about code at k - 3 ? */
	knots[k].x = x3;   knots[k].y = y3;
	knots[k+1].x = x2; knots[k+1].y = y2; 
	knots[k+2].x = x1; knots[k+2].y = y1; 
	assert(knots[k+3].x == x0); 
	assert(knots[k+3].y == y0); 
	assert (knots[k].x == knots[k-3].x);
	assert (knots[k].y == knots[k-3].y);	
	if (showflag != 0) printf("\nNEW: (%d %d) (%d %d) (%d %d) (%d %d) ",
		x0, y0, x1, y1, x2, y2, x3, y3);
	if (showflag != 0) {
		printf("SUCCESS\n");
/*		(void) getch(); */
	}
	merges++;			/* count it */
	hits[chr]++;
	return -1;
}

/* try to patch together - horizontal tangent */ 
int trypatchydown(int k) {
	int xv, yv, x0, y0, x1, y1, x2, y2, x3, y3;
	double rbv, rbt, rbn, ft, fxv, fyv, fxn, fyn, fdx, fdy;
	double fx0, fx1, fx2, fx3, fy0, fy1, fy2, fy3;
	double ax, bx, cx, dx, ay, by, cy, dy;
	 
	if (mergeflag == 0) return 0;
/* 	if (k - 3 < start) return 0; */
	xv = knots[k+3].x; yv = knots[k+3].y; /* place of tangency */
	if (showflag != 0) printf("\nYDOWN: tangent at (%d, %d) ", xv, yv);
	fxv = (double) xv; fyv = (double) yv;
	assert (knots[k+3].y == knots[k+2].y);
	x3 = knots[k].x; y3 = knots[k].y;	
	x2 = knots[k-1].x; y2 = knots[k-1].y;
	fx3 = (double) x3; fy3 = (double) y3;
	fx2 = (double) x2; fy2 = (double) y2;
/* check on angle of turn in short segment */
	if (showflag != 0) printf("- turning (%lg %lg)", fx3 - fx2, fy3 - fy2);
	if (nearhorizontal(fx3 - fx2, fy3 - fy2) == 0) {
		if (showflag != 0) {
			printf(" FAILED\n");
/*			(void) getch(); */
		}
		return 0;
	}
	rbv = distance(fxv, fyv, fx3, fy3);
	rbt = distance(fx3, fy3, fx2, fy2);
	assert (rbt != 0.0);
/*	assert (rbv != 0.0); */
/*	if (rbv == 0.0) combine ? */
	ft = 1.0 + rbv/(3.0 * rbt);		/* estimated t at xv, yv */

	if (showflag != 0) printf("- estimated t = %lg ", ft);
	
	assert (ft >= 1.0);
	if (ft > ftlim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;			/* don't expect to win */
	}

	/* compute coefficients of the two cubics */
	
	x0 = knots[k-3].x; 	x1 = knots[k-2].x;
	fx0 = (double) x0;  fx1 = (double) x1; 
	dx = fx0;
	cx = (fx1 - fx0) * 3.0; 
	bx = ((fx2 - fx1) - (fx1 - fx0)) * 3.0; 
	ax = (fx3 - fx0) + 3.0 * (fx1 - fx2);
	 
	fxn = POLY(ax, bx, cx, fx0, ft); 
	assert (fxn == bezier(x0, x1, x2, x3, ft));

	y0 = knots[k-3].y; 	 y1 = knots[k-2].y;
	fy0 = (double) y0; 	 fy1 = (double) y1; 
	dy = fy0;
	cy = (fy1 - fy0) * 3.0; 
	by = ((fy2 - fy1) - (fy1 - fy0)) * 3.0; 
	ay = (fy3 - fy0) + 3.0 * (fy1 - fy2);
	 
	fyn = POLY(ay, by, cy, fy0, ft); 
	assert (fyn == bezier(y0, y1, y2, y3, ft));

	if (showflag != 0) printf("\nOLD: (%d %d) (%d %d) (%d %d) (%d %d)\n",
		x0, y0, x1, y1, x2, y2, x3, y3);

	fdx = fxv - fxn; fdy = fyv - fyn;
	if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
/*  not clear the following is worth it */
/* 	or maybe always do this ? */
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		rbn = distance(fx3, fy3, fxn, fyn);
		ft = 1.0 + (ft - 1.0) * rbv / rbn;
		fxn = POLY(ax, bx, cx, fx0, ft);
		fyn = POLY(ay, by, cy, fy0, ft);
		fdx = fxv - fxn; fdy = fyv - fyn;		
		if (showflag != 0) printf("Adjusting t = %lg\n", ft);
		if (showflag != 0) printf("offset old (%lg, %lg) ", fdx, fdy);
	}
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0; /* not close enough */
	}
	
	/* compute coefficients of extended cubics */
	
	ax = ax * ft * ft * ft;
	bx = bx * ft * ft;
	cx = cx * ft;
	
	ay = ay * ft * ft * ft;
	by = by * ft * ft;
	cy = cy * ft;
	
	/* compute new knots */

	/* x0 unchanged */
	x1 = round(dx + cx / 3.0);
	x2 = round(dx + (2.0 * cx + bx) / 3.0);
	x3 = round(dx + cx + bx + ax);

	/* y0 unchanged */
	y1 = round(dy + cy / 3.0);
	y2 = round(dy + (2.0 * cy + by) / 3.0);
	y3 = round(dy + cy + by + ay);

	/* snap to knots */

	x3 = xv; y3 = yv; y2 = yv;
	
	/* check that new curve passes near (xb, yb) */
	
 	fxn = bezier(x0, x1, x2, x3, 1/ft); 
	fyn = bezier(y0, y1, y2, y3, 1/ft); 

	fdx = fxn - fx3; 	fdy = fyn - fy3; 		/* old values */
	if (showflag != 0) printf("- offset new (%lg, %lg) ", fdx, fdy);
	if (ABS(fdy) > acrosslim || ABS(fdx) > alonglim) {
		if (showflag != 0) {
			printf("FAILED\n");
/*			(void) getch(); */
		}
		return 0;	/* not close enough */
	}

	/* insert new knots, ready for shift down */
	/* worry about code at k - 3 ? */
	knots[k+3].x = x3; knots[k+3].y = y3;
	knots[k+2].x = x2; knots[k+2].y = y2; 
	knots[k+1].x = x1; knots[k+1].y = y1; 
	knots[k].x = x0;   knots[k].y = y0; 
/*	x0 = knots[k-3].x; 	*/ /*	y0 = knots[k-3].y; 	*/
	assert(knots[k-3].x == knots[k].x);
	assert(knots[k-3].y == knots[k].y);	
	if (showflag != 0) printf("\nNEW: (%d %d) (%d %d) (%d %d) (%d %d) ",
		x0, y0, x1, y1, x2, y2, x3, y3);
	if (showflag != 0) {
		printf("SUCCESS\n");
/*		(void) getch(); */
	}
	merges++;			/* count it */
	hits[chr]++;
	return -1;
}

/*  if you abort splits of short curveto's, can screw up winding number */
/*	int shortie=20;	*/ /* don't try and split if this short */

/* don't split if very shallow extremum ? */
/* don't split if very short ? */

int breaktangents(int start, int end) {  /* break curveto's at tangents */
	int k;
	int dx, dy;		/* not accessed */
	double t;
	
	for (k = start + 3; k < end - 1; k++) {
		if (knots[k].code == 'C') {
			dx = knots[k].x - knots[k-3].x;
			dy = knots[k].y - knots[k-3].y;
/*			if (ABS(dx) < shortie && ABS(dy) < shortie) continue; */
			t = extrema(knots[k-3].x, knots[k-2].x, knots[k-1].x, knots[k].x);
			if (t > 0.0 && t < 1.0) {
				end = shiftup(k, end, 3);
				splitextrema(k, t); 
/*				k = k + 3; */
				if (showflag != 0)
					printf("\nNEXT-X: t = %lg, start = %d, k = %d, end = %d ",
					t, start, k, end);
				if (showflag != 0) 
					printf("\nc(%d) = %c, c(%d) = %c, c(%d) = %c, c(%d) = %c ",
					k-3, knots[k-3].code, k, knots[k].code,
						k+3, knots[k+3].code, k+6, knots[k+6].code);
				if (t > 0.5 && k + 6 < end - 1 && knots[k + 6].code == 'C') {
					if(trypatchxup(k + 3) != 0) 
						end = shiftdown(k + 3 + 1, end, 3); 
				}
				if (t < 0.5 && k - 6 >= start && knots[k - 3].code == 'C') {
					if(trypatchxdown(k - 3) != 0) 
						end = shiftdown(k - 3 + 1, end, 3); 
				}
			}
			t = extrema(knots[k-3].y, knots[k-2].y, knots[k-1].y, knots[k].y);
			if (t > 0.0 && t < 1.0) {
				end = shiftup(k, end, 3); 
				splitextrema(k, t);
/*				k = k + 3; */
				if (showflag != 0) 
					printf("\nNEXT-Y: t = %lg, start = %d, k = %d, end = %d ",
					t, start, k, end);
				if (showflag != 0) 
					printf("\nc(%d) = %c, c(%d) = %c, c(%d) = %c, c(%d) = %c ",
					k-3, knots[k-3].code, k, knots[k].code,
						k+3, knots[k+3].code, k+6, knots[k+6].code);
				if (t > 0.5 && k + 6 < end - 1 && knots[k + 6].code == 'C') {
					if(trypatchyup(k + 3) != 0) 
						end = shiftdown(k + 3 + 1, end, 3); 
				}
				if (t < 0.5 && k - 6 >= start && knots[k - 3].code == 'C') {
					if(trypatchydown(k - 3) != 0) 
						end = shiftdown(k - 3 + 1, end, 3); 
				}
			}
		}
	}
	return end;
}

int trymerges(int start, int end) {  /* try combine certain short curveto's */
	int k;
	
	for (k = start + 3; k < end - 3; k++) { /* look for sequence curveto's */
		if (knots[k].code == 'C' && k + 3 < end - 1 && knots[k+3].code == 'C')
			{
			if (knots[k-3].x == knots[k-2].x) {
				if (showflag != 0) 
					printf("\nNEXT-X: start = %d, k = %d, end = %d ",
					start, k, end);
				if(trypatchxup(k) != 0) 
					end = shiftdown(k + 1, end, 3); 
			}
			else if (knots[k+3].x == knots[k+2].x) {
				if (showflag != 0) 
					printf("\nNEXT-X: start = %d, k = %d, end = %d ",
					start, k, end);
				if(trypatchxdown(k) != 0) 
					end = shiftdown(k + 1, end, 3);
			}
			else if (knots[k-3].y == knots[k-2].y) {
				if (showflag != 0) 
					printf("\nNEXT-Y: start = %d, k = %d, end = %d ",
					start, k, end);
				if(trypatchyup(k) != 0) 
					end = shiftdown(k + 1, end, 3); 
			}
			else if (knots[k+3].y == knots[k+2].y) {
				if (showflag != 0) 
					printf("\nNEXT-Y: start = %d, k = %d, end = %d ",
					start, k, end);
				if(trypatchydown(k) != 0) 
					end = shiftdown(k + 1, end, 3); 
			}
		}
	}
	return end;
}

/* try and merge curvetos - still experimental - OLD version */

/*
void mergecurves(int start, int end) { 
	int k;
	int dy, dx, ds;
	
	if (end - start < 6) return;
	for (k = start + 6; k < end; k++) {
		if (knots[k].code == 'C' && knots[k-3].code == 'C') {
			if(smallangle(knots[k-4].x, knots[k-4].y, 
				          knots[k-3].x, knots[k-3].y,
						  knots[k-3].x, knots[k-3].y, 
						  knots[k-2].x, knots[k-2].y) != 0) {
			if (knots[k-5].x == knots[k-6].x) {
				dy = knots[k-3].y - knots[k-6].y;	
				dx = knots[k-3].x - knots[k-6].x;
				ds = knots[k-2].x - knots[k-6].x;
				if (ABS(dy) + ABS(dx)/2 < mlength && ABS(ds) < msplit) {
					knots[k-5].y = knots[k-2].y;
					end = shiftdown(k-1, end, 3); 
				}
			}
			if (knots[k].x == knots[k-1].x) {
				dy = knots[k].y - knots[k-3].y; 
				dx = knots[k].x - knots[k-3].x;
				ds = knots[k-4].x - knots[k].x;
				if (ABS(dy) + ABS(dx)/2 < mlength && ABS(ds) < msplit) {
					knots[k-4].x = knots[k].x;
					end = shiftdown(k, end, 3); 
				}
			}
			if (knots[k-5].y == knots[k-6].y) {
				dx = knots[k-3].x - knots[k-6].x;	
				dy = knots[k-3].y - knots[k-6].y;
				ds = knots[k-2].y - knots[k-6].y;
				if (ABS(dx) + ABS(dy)/2 < mlength && ABS(ds) < msplit) {
					knots[k-5].x = knots[k-2].x;
					end = shiftdown(k-1, end, 3); 
				}
			}
			if (knots[k].y == knots[k-1].y) {
				dx = knots[k].x - knots[k-3].x; 
				dy = knots[k].y - knots[k-3].y;
				ds = knots[k-4].y - knots[k].y;
				if (ABS(dx) + ABS(dy)/2 < mlength && ABS(ds) < msplit) {
					knots[k-4].y = knots[k].y;
					end = shiftdown(k, end, 3); 
				}
			}			
			}
		}
	}
}
*/

int xcross, ycross; 	/* place to store cross-over for further process */

/* This is not fool proof - we are forced to use  split at extrema first */
/* This could be done more cleanly without using double */
/* Solution of the problem might be more elegant than just the intersection */

int crossover(int xa, int ya, int xb, int yb, 
				int xc, int yc, int xd, int yd) {
	long alphanumer, alphadenom, betanumer, betadenom;
	double alpha, beta;
	
	alphadenom = (long) (xb - xa) * (long) (yd - yc) 
		- (long) (yb - ya) * (long) (xd - xc);
	if (alphadenom == 0L) return 0;
	alphanumer = (long) (xc - xa) * (long) (yd - yc) - 
		(long) (yc - ya) * (long) (xd - xc);
	betadenom = (long) (xd - xc) * (long) (yb - ya) 
		- (long) (yd - yc) * (long) (xb - xa);
	if (betadenom == 0L) return 0;
	betanumer = (long) (yc - ya) * (long) (xb - xa) 
		- (long) (xc - xa) * (long) (yb - ya);
	assert (alphadenom != 0L);
	assert (betadenom != 0L);
	alpha = (double) alphanumer / (double) alphadenom;
	if (alpha <= 0.0 || alpha >= 1.0) return 0;
	beta = (double) betanumer / (double) betadenom;
	if (beta <= 0.0 || beta >= 1.0) return 0;
	xcross = xa + (int) (alpha * (double) (xb - xa));
	ycross = ya + (int) (alpha * (double) (yb - ya));
	return -1;
}

int checkcrossovers(int start, int end) {
	int k;
	int xa, ya, xb, yb, xc, yc, xd, yd;

	k = start;
	xa = knots[k].x, ya = knots[k].y; k++;
	xb = knots[k].x, yb = knots[k].y; k++;
	xc = knots[k].x, yc = knots[k].y; k++;
	while (k < end) {
		xd = knots[k].x, yd = knots[k].y; 
		if (crossover(xa, ya, xb, yb, xc, yc, xd, yd)  != 0) {
/*			printf("Char %d crossover (%d %d) (%d %d) (%d %d) (%d %d)\n",
				chr, xa, ya, xb, yb, xc, yc, xd, yd); */
			printf("%d", chr);
			if (crossoverflag != 0) {
				if (knots[k].code == 'C') { /* split curveto into lineto's */
					if (showcrosses != 0) {
						printf("Char %d crossover (%d %d) (%d %d) (%d %d) (%d %d) ",
							chr, xa, ya, xb, yb, xc, yc, xd, yd); 
						printf("(%c %c %c %c)\n",
							knots[k-3].code, knots[k-2].code, 
								knots[k-1].code, knots[k].code); 
/*						(void) getch(); */
					}
					assert(knots[k-1].code == ' '); 
					assert(knots[k-2].code == ' '); 					
					knots[k-2].x = xcross; knots[k-2].y = ycross;
					knots[k-1].x = xcross; knots[k-1].y = ycross;
					end = shiftdown(k - 1, end, 1); 
					k--;
					knots[k].code = 'L';
					knots[k-1].code = 'L';
				}
				else { /* not a cross-over inside a curveto */
					printf("@");
/* 				do nothing here - does not affect winding number ? */
					if (showcrosses != 0) {
						printf("Char %d crossover (%d %d) (%d %d) (%d %d) (%d %d) ",
							chr, xa, ya, xb, yb, xc, yc, xd, yd); 
						printf("(%c %c %c %c)\n",
							knots[k-3].code, knots[k-2].code, 
								knots[k-1].code, knots[k].code); 
/*						(void) getch(); */
					}
				}
			}
/*			(void) getch(); */
		}
		k++;
		if (xc != xd || yc != yd)
			xa = xb; xb = xc; xc = xd; 	ya = yb; yb = yc; yc = yd;
	}
	return end;
}
	
/*
void checkcrossover(void) {
	int k, start, end;
	for (k = 0; k < nsubpath; k++) {
		start = subpaths[k].start; end = subpaths[k].end;
		checkcrosssub(start, end);
	}
} */


/* ----------------------------------------------------------------*/

void giveup(int code) {	/* graceful exit with meaningful error message */
	fprintf(stderr, " while %s", task);
	if (chr >= 0) fprintf(stderr, " for character %d ", chr);
	else fprintf(stderr, " ");
/* 	fclose(fp_out);	remove(fn_out); */
	if (fgets(line, sizeof(line), fp_in) != NULL) {
		fprintf(stderr, "\nNext line:\n");
		fputs(line, stderr);
	}
	fflush(stderr);
	exit(code);
}

void addknot(int x, int y, int c) { /* add a knot to subpath */
	knots[nknot].x = x;  knots[nknot].y = y;
	knots[nknot].code = (char) c;
	nknot++;
	assert (nknot < MAXKNOTS);
}

int fround(double z) {
	if (z > 0.0) return (int) (z+0.5);
	else if (z < 0.0) return - (int) (-z+0.5);
	else return 0;
}

void enterknot(int c) { /* make knot from next two numbers */
	double fx, fy;
	int x, y;
	
/*	if (sscanf (line, " %d %d", &x, &y) < 2) { */
	if (sscanf (line, " %lg %lg", &fx, &fy) < 2) {
		fprintf(stderr, "Expecting two numbers for lineto or moveto, not:\n");
		fprintf(stderr, "%s", line);
		giveup(1);
	}
	x = fround(fx); y = fround(fy);
	addknot(x, y, c);
}

void enterknots(int c) { /* make knot from next six numbers */
	double fxa, fya, fxb, fyb, fxc, fyc;
	int xa, ya, xb, yb, xc, yc;
	
/*	if( sscanf (line, " %d %d %d %d %d %d", &xa, &ya, &xb, &yb, &xc, &yc) */
	if( sscanf (line, " %lg %lg %lg %lg %lg %lg",
				&fxa, &fya, &fxb, &fyb, &fxc, &fyc)
		<	6) {
		fprintf(stderr, "Expecting six numbers for curveto, not:\n");
		fprintf(stderr, "%s", line);
		giveup(1);
	}
	xa = fround(fxa);	ya = fround(fya);
	xb = fround(fxb);	yb = fround(fyb);
	xc = fround(fxc);	yc = fround(fyc);
	addknot(xa, ya, ' ');
	addknot(xb, yb, ' ');
	addknot(xc, yc, c);
}

void closeloop(void) {			/* finish off subpath */
  int xstart, ystart, inx;

  inx = subpaths[nsubpath].start;
  xstart = knots[inx].x; ystart = knots[inx].y;
  addknot(xstart, ystart, 'H');
}

int checkglitch(int start, int end) {
	int i, xa, ya, xb, yb, xc, yc, xd, yd;

	if (start + 3 >= end) return 0;
	xa = knots[start].x; ya = knots[start].y;
	xb = knots[start+1].x; yb = knots[start+1].y;
	xc = knots[start+2].x; yc = knots[start+2].y;	

	for (i = start + 3; i < end; i++) {
		xd = knots[i].x; yd = knots[i].y;
		if (ya == yd && yb == yc) {
			if (xa == xd && xb == xc) {
				fprintf(stdout, "Glitch %d (%d %d) (%d %d) (%d %d) (%d %d)\n",
					chr, xa, ya, xb, yb, xc, yc, xd, yd); 
/*				(void) getch(); */
			}
		}
		if (ya == yb && yb == yc) {
			if ((xb > xa && xb > xc) || (xb < xa && xb < xc)) {
				fprintf(stdout, "Reversal %d (%d %d) (%d %d) (%d %d)\n",
					chr, xa, ya, xb, yb, xc, yc);
/*				(void) getch(); */
			}
		}
		if (xa == xb && xb == xc) {
			if ((yb > ya && yb > yc) || (yb < ya && yb < yc)) {
				fprintf(stdout, "Reversal %d (%d %d) (%d %d) (%d %d)\n",
					chr, xa, ya, xb, yb, xc, yc);
/*				(void) getch(); */
			}
		}
		xa = xb; ya = yb;
		xb = xc; yb = yc; 
		xc = xd; yc = yd; 
	}
	return 0;
}

void statistics(void) {
	int k, count=0, total=0;
	if (splits > 0) printf("Split %d curveto's ", splits);
	if (merges > 0) printf("Merged %d curveto's ", merges);
	if (straightens > 0) printf("Linearized %d flat curvetos ", straightens);
	if (flattens > 0) printf("Linearized %d almost flat curvetos ", flattens);
	if (colinears > 0) printf("Combined %d colinear lineto's", colinears);
	if (combines > 0) printf("Combined %d lineto's", combines);
	if (splits > 0 || merges > 0 || straightens > 0 ||
		flattens > 0 || colinears > 0 || combines > 0) putc('\n', stdout);
	for (k = 0; k < MAXCHRS; k++) if (hits[k] != 0) count++;
	for (k = 0; k < MAXCHRS; k++) if (seen[k] != 0) total++;
	printf("%d characters (out of %d) modified\n", count, total);
	if (count > 0) {							/* 1996/June/15 */
/*		if (verboseflag) { */
/*			putc('\n', stdout); */
			printf("CHARS: ");
			for (k = 0; k < MAXCHRS; k++)
				if (hits[k] != 0) printf("%d ", k);
/*			putc('\n', stdout); */
/*		} */
	}
}

int eofcount = 0;	/* safety escape */

int getline(FILE *input, char *line) {	/* read a line up to newline */
	if (fgets(line, MAXLINE, input) == NULL) {
		if (newstyle == 0) fprintf(errout, "Unexpected EOF "); 
		if (eofcount++ > 32) {
			statistics();
			giveup(4);
		}
		return EOF;
/*		giveup(4); */
	}
	return 0;
}

long flast;			/* pointer into file at start of character */

int scaninchar(FILE *fp_in, int flag) { /* read outline for one character */
	int start, end, err;
	int chr, width;

	nknot = 0;
	nsubpath = 0;
	task = "scanning in outline";
	if (traceflag) printf ("TASK: %s\n", task);

/*	if (unwindflag != 0 && flag != 0)
		flast = ftell(fp_in);	*/ /* remember start of char */

	if (newstyle != 0) {	/* skip first line --- chr width */
/*		if (strstr(line, " % ") != NULL)   */
		err = getline(fp_in, line); 
		while (*line == '%' || *line == '\n')		/* 1994/Feb/4 */
			err = getline(fp_in, line); 
		if (sscanf (line, "%d %d", &chr, &width) < 2) {
/*		not really an error condition ... */
/*		if (traceflag) {
				fprintf(stderr, "Expecting char code and width, not:\n");
				fprintf(stderr, "%s", line); 
			} */
/*			giveup(1); */
		}
	}
	else {
		if (strstr(line, "} def") == NULL) err = getline(fp_in, line);
	}
	
	err = 0;

/*	while (strstr(line, "} def") == NULL && 
		 strstr(line, "]") == NULL && err != EOF) { */
	for (;;) {
/*		if (strstr(line, "} def") != NULL ||
			strstr(line, "]") != NULL || err == EOF) break; */
		if (*line == '%' || *line == '\n') {	/* ignore comment lines */
			err = getline(fp_in, line);
			if (err == EOF) break;
			continue;
		}			
		if (newstyle != 0 && strstr(line, " s %") != NULL) {
			err = getline(fp_in, line); /* skip over hint replacement calls */
			if (err == EOF) break;
			continue; 
		}
		if (strstr(line, "} def") != NULL ||
			strstr(line, "]") != NULL || err == EOF) break;
		start = nknot;
		subpaths[nsubpath].start = nknot;
/*		while (strstr(line, "closepath") == NULL) {  */ /* 1992/April/8 */
/*		while (strstr(line, "closepath") == NULL &&	
				strstr(line, "h") == NULL && err != EOF) { */
		for (;;) {
/*			if (strstr(line, "closepath") != NULL ||
				strstr(line, "h") != NULL || err == EOF) break; */
			if (*line == '%' || *line == '\n') {	/* ignore comment lines */
				err = getline(fp_in, line);
				if (err == EOF) break;
				continue; 
			}			
			if (newstyle != 0 && strstr(line, " s %") != NULL) {
				err = getline(fp_in, line); /* skip hint replacement calls */
				continue; 
			}
			if (strstr(line, "closepath") != NULL ||
				strstr(line, "h") != NULL || err == EOF) break; 
			if (strstr(line, "moveto") != NULL) enterknot('M');
			else if (strstr(line, "m") != NULL) enterknot('M'); /* ??? */
			else if (strstr(line, "lineto") != NULL) enterknot('L');
			else if (strstr(line, "l") != NULL) enterknot('L');	/* ??? */	
			else if (strstr(line, "curveto") != NULL) enterknots('C');
			else if (strstr(line, "c") != NULL) enterknots('C'); /* ??? */
			else {
				fprintf(stderr, "Can't understand: %s", line);
				giveup(7);
			}
			err = getline(fp_in, line);
		}
		if (strstr(line, "reverse") != NULL) {
			subpaths[nsubpath].reverse = 1;
			if (flag != 0)
				printf("Flipping reversal of subpath %d in char %d\n",
					nsubpath, chr);
		}
		else subpaths[nsubpath].reverse = 0;

		if (traceflag != 0) printf("End of subpath \n");
		if (knots[nknot-1].x != knots[start].x ||
			knots[nknot-1].y != knots[start].y) {
/*			fprintf(stdout, "open in %d ",	chr); */
			if (complainopen != 0) 	printf("open "); 
			addknot(knots[start].x, knots[start].y, 'L');
		}

		closeloop();
		end = nknot;

		if (knots[start].code != 'M') {
			showsubpathsub(start, end);
			fflush(stdout);
			(void) _getch();   
		}
		fflush(stdout);
		if (debugflag != 0) {
			assert(knots[start].code == 'M');
			assert(knots[end-1].code == 'H');
			assert(knots[end-1].x == knots[start].x);
			assert(knots[end-1].y == knots[start].y);
			assert(knots[end-2].code == 'L' ||	knots[end-2].code == 'C');
			if (knots[end-2].x != knots[start].x ||
				knots[end-2].y != knots[start].y) {
				fprintf(stdout, "Path not closed %d (%d %d) (%d %d)\n",
					chr, knots[end-2].x, knots[end-2].y,
						 knots[start].x, knots[start].y);
			} 
/*			assert(knots[end-2].x == knots[start].x); */
/*			assert(knots[end-2].y == knots[start].y); */
		}

		if (flag != 0) {
			(void) checkglitch(start, end); /* ? */
			if (splitextremaflag != 0) end = breaktangents(start, end);
			if (crossoverflag != 0) end = checkcrossovers(start, end);
			if (moremerges != 0) {
				(void) rearrange(start, end);
				end = trymerges(start, end);
				(void) rearrange(start, end);
			}
			if (straightenflag != 0) end = straightencurves(start, end);
			if (flattenflag != 0) end = flattencurves(start, end);
			if (colinearflag != 0) end = mergelines(start, end);
			if (combineflag != 0) end = combinelines(start, end);
		}
		
		subpaths[nsubpath].end = end; nknot = end;
		nsubpath++;
		assert (nsubpath < MAXSUBPATHS);
		err = getline(fp_in, line); 
	}
	 return err;
}

/* --- following is stuff for computing winding numbers --- */

long dotproduct(int xab, int yab, int xbc, int ybc) {
	long dot;
	dot = (long) xab * (long) xbc + (long) yab * (long) ybc; 
	return dot;
/*  return (double) xab * (double) xbc + (double) yab * (double) ybc; */
}

long crossproduct(int xab, int yab, int xbc, int ybc) {
	long cross;
	cross = (long) xab * (long) ybc - (long) yab * (long) xbc;
	return cross;
/*  return xab * (double) ybc - (double) yab * (double) xbc; */
}

double angle(int xab, int yab, int xbc, int ybc) {
  long lsint, lcost;
/*  double sint, cost; */

  if ((xab == 0 && yab == 0) || (xbc == 0 && ybc == 0)) {
    fprintf(stderr, "Zero length vector");
    giveup(5);
  }
  lsint =  crossproduct(xab, yab, xbc, ybc);
  lcost =  dotproduct(xab, yab, xbc, ybc);
  if (lsint == 0 && lcost < 0) {
	  fprintf(stdout, "\nAntiparallel in %d: ", chr);
	  return 10.0;	/* an impossible value */
  }
  assert(lsint != 0 || lcost != 0);
  return atan2((double) lsint, (double) lcost);
}

void setbbox(int k) {
	int x, y, code;
	int start, end, i;
	int xll, yll, xur, yur;
	
	start = subpaths[k].start;  end = subpaths[k].end;
	x = knots[start].x; y = knots[start].y;
	xll = x; yll = y; xur = x, yur = y;
	for (i = start + 1; i < end; i++) {
		x = knots[i].x; y = knots[i].y;
		code = knots[i].code;
		if (code != ' ') { /* ignore guide knots */
			if (x < xll) xll = x; 	if (y < yll) yll = y;
			if (x > xur) xur = x; 	if (y > yur) yur = y;
		}
		else if (knots[i-1].code == ' ') { /* try average ? */
			x = (knots[i].x + knots[i-1].x)/2;
			y = (knots[i].y + knots[i-1].y)/2;
			if (x < xll) xll = x; 	if (y < yll) yll = y;
			if (x > xur) xur = x; 	if (y > yur) yur = y;
		}
	}

     subpaths[k].xll = xll;
     subpaths[k].yll = yll;
     subpaths[k].xur = xur;
     subpaths[k].yur = yur;
}

double getturn(int k) {
	int start, end, i;
	int xa, ya, xb, yb, xc, yc;
	int xab, yab, xbc, ybc;
	double turn=0.0, dturn, theta;

	start = subpaths[k].start;
	end = subpaths[k].end;

	if(end < start + 3) {
		fprintf(stderr, "Subpath too short (%d) in char %d\n",
			end - start, chr);
		return 0.0;
	}

	xb = knots[start].x; yb = knots[start].y;

	i = start;
	for (;;) {
		xc = knots[i].x; yc = knots[i].y;
		if (xb != xc || yb != yc) {
			xbc = xc - xb; ybc = yc - yb;
			xa = xb; ya = yb; xb = xc; yb = yc; 
			xab = xbc; yab = ybc; 
			break;
		}
		i++;
	}

	assert(xab != 0 || yab != 0);	/* xab yab initialized ? */

	while (i < end) {
		xc = knots[i].x; yc = knots[i].y;
		if (xb != xc || yb != yc) { /* ignore coincident knots */
			xbc = xc - xb; ybc = yc - yb;
/*			printf("%lg ", turn); */
			theta = angle(xab, yab, xbc, ybc);
			if (theta == 10.0)	{	/* error code */
				fprintf(stdout, "(%d %d) (%d %d) (%d %d) ",
					xa, ya, xb, yb, xc, yc);
/*				putc(7, stdout); */
/*				(void) getch();  */
			}
			else turn = turn + theta;
			xa = xb; ya = yb; xb = xc; yb = yc; 
			xab = xbc; yab = ybc; 
		}
		i++;
	}

	i = start + 1;

	for(;;) {
		xc = knots[i].x; yc = knots[i].y;
		if (xb != xc || yb != yc) { /* ignore coincident knots */
			xbc = xc - xb; ybc = yc - yb;
			theta = angle(xab, yab, xbc, ybc);
			if (theta == 10.0)		/* error code */
				fprintf(stdout, "(%d %d) (%d %d) (%d %d)",
					xa, ya, xb, yb, xc, yc);
			else turn = turn + theta;
			break;
		}
		i++;
	}

/* check whether total angle turned through is + or - two pi */
	dturn = turn - 2.0 * pi;
	if (dturn < -0.01 || dturn > 0.01) {
		dturn = turn + 2.0 * pi;
		if (dturn < -0.01 || dturn > 0.01) {
			printf("Char %d turn is %lg for subpath %d \n",	chr, turn, k); 
/*			(void) getch(); */
		}
	}
	return turn;
}

double getarea(int k) {
	int start, end, i;
	int xa, ya, xb, yb;
	double area=0.0;
	long darea;

	start = subpaths[k].start;
	end = subpaths[k].end;

	xa = knots[start].x; ya = knots[start].y;

	for (i = start + 1; i < end; i++) {
		xb = knots[i].x; yb = knots[i].y;
		darea = (long) xa * (long) yb - (long) ya * (long) xb;
		area = area + (double) darea;
		xa = xb; ya = yb; 
	}
	return area;
}

int inside(int i, int j) {
     int xlli, ylli, xuri, yuri;
     int xllj, yllj, xurj, yurj;
     xlli = subpaths[i].xll; ylli = subpaths[i].yll;
     xuri = subpaths[i].xur; yuri = subpaths[i].yur;
     xllj = subpaths[j].xll; yllj = subpaths[j].yll;
     xurj = subpaths[j].xur; yurj = subpaths[j].yur;
/*	 printf(" (%d %d %d %d) (%d %d %d %d) ",
		 xlli, ylli, xuri, yuri, xllj, yllj, xurj, yurj); */
     if (xlli > xllj && ylli > yllj && xuri < xurj && yuri < yurj) return -1;
     else return 0;
   }

int getoutside(int k) { /* see if bbox is not inside any others */
     int i, flag = -1;
     for (i = 0; i < nsubpath; i++) {
       if (i == k) continue;
       if (inside(k, i) != 0) {
		   flag = 0;
		   break;
	   }
	 }
     return flag;
}

void analchar(void) { /* subpaths and knots of character */
     int k;
	 int outside;		/* use before define ? */
	 double turn;
	 double area;		/* use before define ? */

     for (k=0; k < nsubpath; k++) {
		 setbbox(k);
     }
	 turn = 0;
     for (k=0; k < nsubpath; k++) {
		 turn =  getturn(k);
		 subpaths[k].turn =  turn;
		 area =  getarea(k);
		 subpaths[k].area =  area;		 
		 if (verboseflag != 0) printf(" %lg ", turn);
/*		 if (turn > 0) printf("+");
		 else printf("-"); */
     }
	 outside = 0;
     for (k=0; k < nsubpath; k++) {
		 outside = getoutside(k);
		 subpaths[k].outside = outside;
		 if (verboseflag != 0) printf(" %d ", outside);
     }
	 if ((turn > 0 && outside != 0) ||
		 (turn < 0 && outside == 0)) putc('+', stdout);
	 else {
		 putc('-', stdout); 
		 if (complainflag != 0) {
			 printf(" %d ", chr);
/*			 putc(7, stdout);  */
/*			 (void) getch(); */
		 }
	 }
   }
   
char *expandcode(int c) {
	if (newstyle != 0) {
		switch(c) {
			case 'L': return "l"; 
			case 'C': return "c";
			case 'M': return "m";
			case 'H': return "h";
			default: {
				fprintf(stderr,
					"Error: char %c not valid code", c);
				giveup(3);
			}
		}
	}
	else {
		switch(c) {
			case 'L': return "lineto"; 
			case 'C': return "curveto";
			case 'M': return "moveto";
			case 'H': return "closepath";
			default: {
				fprintf(stderr,
					"Error: char %c not valid code", c);
				giveup(3);
			}
		}
	}
	return "";		// keep compiler quiet
}

void dumpchar(FILE *fp_out) {
	int x, y, k;
	int start, end, i, code;

	for (k=0; k < nsubpath; k++) {
		start = subpaths[k].start;    end = subpaths[k].end;

		i = start;
		while (i < end) {
			code = knots[i].code;
			if (code != 'H') {
				x = knots[i].x; y = knots[i].y; i++;
/*				if (closepaths == 0 && i >= end-2 && code == 'L') { */
				if (closepaths == 0 && i >= end-1 && code == 'L') {
/*					printf("start %d i %d end %d\n", start, i, end); */
/*					printf("x  %d y  %d c %c\n", x, y, code); */
/*					printf("xo %d yo %d\n", knots[start].x, knots[start].y); */
					if (x == knots[start].x && y == knots[start].y) continue;
				}
				if (newstyle == 0) fprintf(fp_out, "    ");
				fprintf(fp_out, "%d %d ", x, y);
				if (code == ' ') {
					code = knots[i].code;
					if (code != ' ') showsubpath(k); 
					assert(code == ' ');
					x = knots[i].x; y = knots[i].y; i++;
					fprintf(fp_out, "%d %d ", x, y);
					code = knots[i].code;
					assert(code == 'C');
					x = knots[i].x; y = knots[i].y; i++;
					fprintf(fp_out, "%d %d ", x, y);
				} 
			}
			else {
				i++;
				if (newstyle == 0) fprintf(fp_out, "    ");
			}
			fprintf(fp_out, "%s\n", expandcode(code));
		}
	}
}

int copytochars(FILE *fp_in, FILE *fp_out) {
	double size, scale;

	getline(fp_in, line);
	while (*line == '%' || *line == '\n') {
		fputs(line, fp_out);
		getline(fp_in, line);
	}

	if (sscanf (line, "%lg %lg", &size, &scale) == 2) { /* new style */
/*		fprintf(fp_out, "%s", line); */
		fputs(line, fp_out);
		getline(fp_in, line);							/* read BBox */
		while (*line == '%' || *line == '\n') {
			fputs(line, fp_out);
			getline(fp_in, line); 
		}
/*		fprintf(fp_out, "%s", line); */
		fputs(line, fp_out);
		return 1;
	}
	else {
		while (strstr(line, "/CharacterDefs") == NULL) { /* old style */
			fprintf(fp_out, "%s", line);
/*			getline(fp_in, line); */
			if (getline(fp_in, line) == EOF) {
				fprintf(stderr, "Bad OUT file\n");	/* 1996/Apr/8 */
				exit(1);
			}
		}
		fprintf(fp_out, "%s", line);
		return 0;
	}
}

void reversesubpath(int k) { /* reverse subpath number k */
	struct knot temp;
	int start, end, i, no;
	char lastcom, com;

/*	if (chr == 123) showsubpath(k); */
	start = subpaths[k].start;
	end = subpaths[k].end;
	assert(knots[end-1].x == knots[end-2].x);
	assert(knots[end-1].y == knots[end-2].y);
	no = (end - 1 - start) / 2;
	for (i = 0; i < no; i++) {
		temp = knots[start + i];
		knots[start + i] = knots[end - 2 - i];
		knots[end - 2 - i] = temp;
	}
	lastcom = knots[start].code;
	knots[start].code = 'M';
	for (i = start + 1; i < end - 1; i++) {
		com = knots[i].code;
		if (com != ' ') {
			knots[i].code = lastcom;
			lastcom = com;
		}
	}
	knots[end - 1].code = 'H';
/*	if (chr == 123) {
		showsubpath(k);
		(void) getch();
	} */
}	

void unwindifneeded(FILE *fp_in) {
	if (unwindflag != 0) {
		fseek(fp_in, flast, SEEK_SET);	/* seek back to start of character */
		getline(fp_in, line);
		/* reread outline for one character */
		if (scaninchar(fp_in, 0) == EOF) {
			fprintf(errout, "EOF in unwindifneeded\n");
		}
		/* reread subpaths, but leave flags intact */
	}
}

void reverseifneeded(void) {
	int k;
	if (reverseflag != 0) {
/*		for (k = 0; k < nsubpath; k++) {
			if ((subpaths[k].outside == 0 && subpaths[k].turn > 0.0) ||
				(subpaths[k].outside != 0 && subpaths[k].turn < 0.0)) {
				reversesubpath(k);
			}
		} */
		for (k = 0; k < nsubpath; k++) {
			if (subpaths[k].reverse == 0) {
				if ((subpaths[k].outside == 0 && subpaths[k].area > 0.0) ||
					(subpaths[k].outside != 0 && subpaths[k].area < 0.0)) {
					reversesubpath(k);
				}
			}
			else {
				if ((subpaths[k].outside != 0 && subpaths[k].area > 0.0) ||
					(subpaths[k].outside == 0 && subpaths[k].area < 0.0)) {
					reversesubpath(k);
				}
			}
				
		}
	}
}

int doallchars(FILE *fp_in, FILE *fp_out) {
	int width, k, err;

	if (traceflag != 0) printf("Doing all characters now\n");
	if (unwindflag != 0) flast = ftell(fp_in);
	err = getline(fp_in, line);
	if (err == EOF) return EOF;

	while (strstr(line, "end def") == NULL && err != EOF) {
		task = "scanning for next outline";
		if (traceflag) printf ("TASK: %s\n", task);
/*		if (traceflag != 0) printf("%s", line);		*/
		if (strstr(line, "/.notdef") != NULL) {
			fprintf(fp_out, "%s", line);
			if (traceflag != 0) printf("%s", line);
			if (unwindflag != 0) flast = ftell(fp_in);
			err = getline(fp_in, line);
			if (err == EOF) return EOF;		/* break */
			if (traceflag != 0) printf("%s", line);
		}
		if (traceflag != 0) printf("%s", line);
		if (strstr(line, "} def") != NULL) {
			err = getline(fp_in, line);
			if (err == EOF) return EOF;		/* break */
		}
		if (strstr(line, "end def") != NULL) break;			/* ? */
		if (newstyle != 0) {	/* new style */
			err = getline(fp_in, line);
/*			while (*line == '%' || *line == '\n') {	*/	/* 96/Apr/6 */
			while (*line == '%' || *line == '\n' || *line == ']') {
				if (getline(fp_in,line) == EOF) break;
			}
			if (err == EOF) return EOF;		/* break */
			if (sscanf (line, "%d %d", &chr, &width) < 2) {
				fprintf(stderr, "Expecting char code and width, not:\n");
				fprintf(stderr, "%s", line);
				giveup(1); 
			}
		}
		else if (sscanf(line, " /char%d ", &chr) != 1) { /* old style */
			fprintf(stderr, "Don't understand: %s\n", line);
			for(k=0; k < MAXCHRS; k++) {
/*				(void) getch(); */
				err = getline(fp_in, line);
				if (err == EOF) return EOF;		/* break */
				fprintf(stderr, "%s", line); 
			}
			giveup(5);	/* was unreachable */
		}
		if (verboseflag != 0) printf("\n(%d) ", chr);
		seen[chr]++;
		fprintf(fp_out, "%s", line);
		if (traceflag != 0) printf("First line: %s", line);

		err = scaninchar(fp_in, -1);
		if (err == EOF) {
			fprintf(errout, "EOF in doallchars\n");
		}

		task = "analyzing subpaths";
		if (traceflag != 0) printf("Analyzing subpaths\n"); 
		analchar();
		task = "rereading subpaths";
		if (traceflag != 0) printf("Rereading subpaths\n");
		unwindifneeded(fp_in);		
		task = "reversing some subpaths";
		if (traceflag != 0) printf("Reversing some subpaths\n");
		reverseifneeded();
		task = "dumping character";
		if (traceflag != 0) printf("Dumping character\n");
		dumpchar(fp_out);
		if (strstr(line, "/char") == NULL) 
			fprintf(fp_out, "%s", line);			/* ? */
		if (traceflag != 0) printf("%s", line);
		if (unwindflag != 0) flast = ftell(fp_in);
		if (err == EOF) return EOF;		/* break */
		if (newstyle == 0) {
			err = getline(fp_in, line); /* ??? */
			if (err == EOF) return EOF;	/* break */
		}
	}
	if (newstyle == 0) fprintf(fp_out, "%s", line);
	return err;
}

void copytoEOF(FILE *fp_in, FILE *fp_out) {
	int err;
	char *s;

	err = getline(fp_in, line);
	if (err == EOF) return;
	while(strstr(line, "definefont") == NULL)  {
		if ((s = strstr(line, "eofill")) != NULL) strcpy(s, s+2);
		fprintf(fp_out, "%s", line);
		err = getline(fp_in, line);
		if (err == EOF) return;
	}
/*	while(fgets(line, MAXLINE, input) != NULL)  */
	  fprintf(fp_out, "%s", line); 
}


#ifdef IGNORE
void extension(char *fname, char *ext) { /* supply extension if none */
    if (strchr(fname, '.') == NULL) {
		strcat(fname, "."); strcat(fname, ext);
	}
}

void forceexten(char *fname, char *ext) { /* change extension, if present */
	char *s;
    if ((s = strchr(fname, '.')) == NULL) {
		strcat(fname, "."); strcat(fname, ext);
	}
	else strcpy(s+1, ext);		/* give it default extension */
}
#endif

void extension(char *fname, char *ext) { /* supply extension if none */
	char *s, *t;
    if ((s = strrchr(fname, '.')) == NULL ||
		((t = strrchr(fname, '\\')) != NULL && s < t)) {
			strcat(fname, "."); 
			strcat(fname, ext);
	}
}

void forceexten(char *fname, char *ext) { /* change extension if present */
	char *s, *t;
    if ((s = strrchr(fname, '.')) == NULL ||
		((t = strrchr(fname, '\\')) != NULL && s < t)) {
			strcat(fname, "."); 
			strcat(fname, ext);
	}
	else strcpy(s+1, ext);		/* give it default extension */
}

void showusage(char *s) {
	fprintf (errout, "\
Correct usage is:\n\n\
%s [-[v][s][m][c] [-e <ext>] <file-1> <file-2> ...\n\n", s);
	fprintf (errout, "\
\tv: verbose mode\n\
\tt: tracing mode\n\
\tn: suppress output\n\
\tu: unwind only (split and uncross to get winding, then reread original)\n\
\tg: give char number when bad winding number seen\n\
\tq: suppress subpath reversals\n\
\tx: the works => s, m, c, r, f, l\n\
\ts: split curveto's at extrema\n\
\tm: merge short curveto's generated by splitting\n\
\tc: remove crossovers\n\
\tr: make additional merging pass\n\
\tf: flatten nearly flat curveto's\n\
\tl: combine colinear lineto's\n\
\to: complain about open subpaths\n\
\tz: write lineto closing path\n\
");
/*	fprintf (errout, "\
\tp: next argument is path for output file\n"); */
/*	fprintf (errout, "\
\te: next argument is extension to use on ouput file (default '%s')\n", 
	ext); */
	exit(1);
}

void decodeflag (int c) {
/*	printf ("FLAG: %c%n", c); */
	switch(c) { 
		case 's': splitextremaflag = 1; break;
		case 'm': mergeflag = 1; break;
		case 'r': moremerges = 1; break;
		case 'f': flattenflag = 1; break;
		case 'a': straightenflag = 0; break;
		case 'b': colinearflag = 0; break;
		case 'q': reverseflag = 0; break;
		case 'l': combineflag = 1; break;
		case 'g': complainflag = 1; break;
		case 'x': splitextremaflag = 1; mergeflag = 1; moremerges = 1;
		          flattenflag = 1; combineflag = 1;	crossoverflag = 1;
				  break;
		case 'u': unwindflag = 1; splitextremaflag = 1; crossoverflag = 1;
				  break;
		case 'c': crossoverflag = 1; break;
		case 't': traceflag = 1; showflag = 1; break;		
		case 'v': verboseflag = 1; break;
		case '?': detailflag = 1; break;
		case 'o': complainopen = 1; break;
		case 'z': closepaths = 1; break;
		case 'n': nulloutput = 1; break;
		case 'p': pathflag = 1; break;
		case 'e': extenflag = 1; break;
		default: {
				fprintf(stderr, "Invalid command line flag '%c'", c);
				giveup(7);
		}
	}
}

int main(int argc, char *argv[]) {
/*  FILE *fp_in, *fp_out; */
  char fn_in[FILENAME_MAX], fn_out[FILENAME_MAX];
  unsigned int i;
  char *s;
  int c, k, m, err;
  int firstarg=1;

  chr = -1;

  if (argc < 2) showusage(argv[0]);

  task = "interpeting command line";
  if (traceflag) printf ("TASK: %s\n", task);

/*  while (argv[firstarg][0] == '-') */ /* check for command flags */
  while (firstarg < argc && argv[firstarg][0] == '-') { /* command flags */
/*		printf("LENGTH = %d\n", strlen(argv[firstarg]) ); */
		for(i = 1; i < strlen(argv[firstarg]); i++) {
			if ((c = argv[firstarg][i]) == '\0') break;
			else decodeflag(c);
		}
		firstarg++;
		if (extenflag != 0) {
			ext = argv[firstarg]; firstarg++; extenflag = 0;
		}
		if (pathflag != 0) {
			path = argv[firstarg]; firstarg++; pathflag = 0;
		}
	}

	if (detailflag) showusage(argv[0]);

  for (m = firstarg; m < argc; m++) {

	  task = "opening files";
	  if (traceflag) printf ("TASK: %s\n", task);

	  splits = 0; merges = 0; flattens = 0; straightens = 0;
	  colinears = 0; combines = 0;

	  for (k = 0; k < MAXCHRS; k++) hits[k] = 0;		/* reset hit list */
	  for (k = 0; k < MAXCHRS; k++) seen[k] = 0;		/* reset seen list */

	  strcpy(fn_in, argv[m]);
/*	  extension(fn_in, "ps"); */
/*	  extension(fn_in, "out"); */
/*	  if (verboseflag != 0)  */
		  printf("Processing font file %s\n", fn_in);
	  if (strcmp(path, "") != 0) {
		  strcpy(fn_out, path);
		  strcat(fn_out, "\\");
		  if ((s=strrchr(fn_in, '\\')) != NULL) s++;
		  else if ((s=strrchr(fn_in, ':')) != NULL) s++;
		  else s = fn_in;
		  strcat(fn_out, s);  	/* copy input file name minus path */
	  }
	  else {
#if CURRENTDIRECT != 0
		if ((s=strrchr(fn_in, '\\')) != NULL) s++;
		else if ((s=strrchr(fn_in, ':')) != NULL) s++;
		else s = fn_in;
		strcpy(fn_out, s);  	/* copy input file name minus path */
#else
		strcpy(fn_out, fn_in);  /* copy input file name */
#endif
	  }
	  forceexten(fn_out, ext);	/* change extension */
	  if (verboseflag != 0) printf("Output file: %s\n", fn_out);
		
	  if (nulloutput != 0) strcpy(fn_out, "NULL");
	  extension(fn_in, "out");	/* 1996/Apr/7 */
	  if ((fp_in = fopen(fn_in, "r")) == NULL) {
		  forceexten(fn_in, "out");
		  if ((fp_in = fopen(fn_in, "r")) == NULL) {
			  fprintf(stderr, "\n"); perror(fn_in); giveup(2);
		  }
	  }
	  if ((fp_out = fopen(fn_out, "w")) == NULL) {
		  fprintf(stderr, "\n"); perror(fn_in); giveup(2);
	  }

	 task = "scanning to character definitions";
	 if (traceflag) printf ("TASK: %s\n", task);
	 newstyle = copytochars(fp_in, fp_out);
	 if (traceflag != 0) {
		 if (newstyle != 0) printf("New Style file\n");
	 }
	 if (newstyle != 0) fprintf(fp_out, "]\n");
	 task = "processing all characters";
	 if (traceflag) printf ("TASK: %s\n", task);
	 err = doallchars(fp_in, fp_out);
	 task = "copying trailer information";
	 if (traceflag) printf ("TASK: %s\n", task);
	 if (newstyle == 0 && err != EOF) copytoEOF(fp_in, fp_out);  

	 printf("\n");
	 task = "closing files";
	 if (traceflag) printf ("TASK: %s\n", task);
	 statistics();
	 fclose(fp_in);
	 if (ferror(fp_out) != 0) {
		 fprintf(stderr, "Output error");
		 perror(fn_out); giveup(2);
	 }
	 fclose(fp_out);  
  }
  task = "finishing up";
 if (traceflag) printf ("TASK: %s\n", task);
  if (argc - firstarg > 1) printf( "Processed %d font files\n",
	  argc - firstarg);
  return 0;
}

/* there is a lot of repetition in trypatchxup etc */
/* trade-off here between how much we want to stick close to original */
/* versus how concise we want to make the output */

/* avoid replication when "/char<n> {} def" is seen - cminch problem */
/* fonts without complete character set yield problems /char<n> {} def */

/* should complain about antiparallel segments */

/* should check for three knots coinciding... */

/* may print an extra `h' line at end in newstyle ... */

/* DON'T COMPILE WITH TOO HIGH OPTIMIZATION - induces bugs at run-time */
